﻿using System;
using System.Collections.Generic;

using System.Text;
using System.IO;


namespace ImageTagger
{
    

    class ImageTag
    {
        public bool used;
        public bool prevused;
        public string name;
        public string description;
        public ImageTag base_tag;

        public ImageTag(TagReader tr, string name_v, string description_v, string basic_class)
        {
            used = false;
            prevused = false;
            name = name_v;
            description = description_v;
            if (basic_class == null)
            {
                if (tr.tags.Count>0)
                    base_tag = tr.tags[0];

            }
            else
                foreach(ImageTag it in tr.tags)
                    if (it.name == basic_class)
                    {
                        base_tag = it;
                        break;
                    }
            if (base_tag == null)
            {
                if (tr.tags.Count > 0)
                    base_tag = tr.tags[0];
            }
        }

        protected ImageTag() { }
    }

    public struct Trapezoid_t
    {
        public int Left_edge;
        public int Right_edge;
        public int Left_ledge;
        public int Right_ledge;
    }

    class BadTagName : Exception { }

    class ImageColourTag
    {
        public ImageTag It;
        private Trapezoid_t H_Criterion;
        private Trapezoid_t S_Criterion;
        private Trapezoid_t V_Criterion;
        public int Threshold;
  
        public void AssignH(int Left_edge, int Left_ledge, int Right_ledge, int Right_edge)
        {
            H_Criterion.Left_edge = Left_edge;
            H_Criterion.Right_edge = Right_edge;
            H_Criterion.Left_ledge = Left_ledge;
            H_Criterion.Right_ledge = Right_ledge;
        }

        public void AssignS(int Left_edge, int Left_ledge, int Right_ledge, int Right_edge)
        {
            S_Criterion.Left_edge = Left_edge;
            S_Criterion.Right_edge = Right_edge;
            S_Criterion.Left_ledge = Left_ledge;
            S_Criterion.Right_ledge = Right_ledge;
        }

        public void AssignV(int Left_edge, int Left_ledge, int Right_ledge, int Right_edge)
        {
            V_Criterion.Left_edge = Left_edge;
            V_Criterion.Right_edge = Right_edge;
            V_Criterion.Left_ledge = Left_ledge;
            V_Criterion.Right_ledge = Right_ledge;
        }

        private float CheckComponent(Trapezoid_t component, int value)
        {
            if (value < component.Left_edge) return .0f;
            if (value > component.Right_edge) return .0f;
            if (value < component.Left_ledge) return ((float)(value - component.Left_edge)) / (component.Left_ledge-component.Left_edge);
            if (value > component.Right_ledge) return ((float)(component.Right_edge - value)) / (component.Right_edge - component.Right_ledge);
            return 1.0f;
        }

        public float AppraisePixel(int H, int S, int V)
        {
            float dt = 1;
            dt *= CheckComponent(H_Criterion, H);
            dt *= CheckComponent(S_Criterion, S);
            dt *= CheckComponent(V_Criterion, V);
            return dt;
        }

        private ImageColourTag() { }
        public ImageColourTag(string tag, TagReader t)
        {
            It = t.GetTag(tag);
            if (It == null) throw new BadTagName();
        }


    }

    class TagReader
    {
        private ImageTag root;
        public System.Collections.Generic.List<ImageTag> tags = new System.Collections.Generic.List<ImageTag>();
        public System.Collections.Generic.List<ImageColourTag> colours = new System.Collections.Generic.List<ImageColourTag>();

        public ImageTag GetTag(string str)
        {
            foreach (ImageTag it in tags)
                if (it.name == str) return it;
            return null;
        }

        public ImageColourTag GetColourTag(string str)
        {
            foreach (ImageColourTag it in colours)
                if (it.It.name == str) return it;
            return null;
        }

        public TagReader()
        { 
            root = new ImageTag(this,"ROOT", "ROOT", null);
        }

        public void ParseConfigFile(string file)
        {
            tags.Clear();
            tags.Add(root);
            StreamReader f = new StreamReader(file);
            string cur;
            while (true)
            {
                cur = f.ReadLine();
                if (cur == null) break;
                cur.ToLower();
                if (cur.CompareTo("[tags]") == 0) ProcessTagsBlock(f);
                if (cur.CompareTo("[descriptions]") == 0) ProcessDescriptionBlock(f);
                if (cur.CompareTo("[colours]") == 0) ProcessColoursBlock(f);
                if (cur.CompareTo("[colors]") == 0) ProcessColoursBlock(f);
            }
            f.Close();
        }


        private bool ProcessTagsBlock(StreamReader sr)
        {
            string cur;
            string[] tags_s;
            ImageTag tt;
            char[] separators = new char [2] {' ', '\t'};
            while (true)
            {
                if (sr.Peek() == '[') return true;
                cur = sr.ReadLine();
                if (cur == null) return false;
                if (cur == "") continue;
                tags_s = cur.Split(separators);
                ImageTag t = new ImageTag(this,tags_s[0].Trim(), tags_s[0].Trim(), null);
                tags.Add(t);
                for (int i = 1; i < tags_s.Length; i++)
                    if (tags_s[i].Trim() == "") continue;
                    else
                    {
                        tt = new ImageTag(this, tags_s[i].Trim(), tags_s[i].Trim(), t.name);
                        tags.Add(tt);
                    }
            }
        }

        private bool ProcessDescriptionBlock(StreamReader sr)
        {
            string cur;
            string tag;
            string description;
            int i;
            while (true)
            {
                i = 0;
                if (sr.Peek() == '[') return true;
                cur = sr.ReadLine();
                if (cur == null) return false;
                for (;( cur[i] != ' ' )&& (cur[i] != '\t'); i++) ;
                tag = cur.Substring(0, i).Trim();
                description = cur.Substring(i).Trim();
                if (tag == "") continue;
                if (description == "") continue;
                foreach(ImageTag e in tags)
                    if (e.name == tag)
                    {
                        e.description = description;
                        break;
                    }

            }
        }
        private bool ProcessColoursBlock(StreamReader sr)
        {           
            string cur;
            string[] raw_s;
            char[] separators = new char [2] {' ', '\t'};
            string[] str_s = new string[14];
            while (true)
            {
                if (sr.Peek() == '[') return true;
                cur = sr.ReadLine();
                if (cur == null) return false;
                if (cur == "") continue;
                raw_s = cur.Split(separators);
                int j = 0;
                for (int i = 0; i < raw_s.Length; i++)
                    if (raw_s[i].Trim() == "") continue;
                    else
                    {
                        str_s[j] = raw_s[i].Trim();
                        j++;
                    }
                if (j != 14) return false;
                ImageTag t = GetTag(str_s[0]);
                if (t == null) 
                    return false;
                ImageColourTag ict = new ImageColourTag(str_s[0],this);
                ict.AssignH(Int32.Parse(str_s[1]), Int32.Parse(str_s[2]), Int32.Parse(str_s[3]), Int32.Parse(str_s[4]));
                ict.AssignS(Int32.Parse(str_s[5]), Int32.Parse(str_s[6]), Int32.Parse(str_s[7]), Int32.Parse(str_s[8]));
                ict.AssignV(Int32.Parse(str_s[9]), Int32.Parse(str_s[10]), Int32.Parse(str_s[11]), Int32.Parse(str_s[12]));
                ict.Threshold = Int32.Parse(str_s[13]);
                colours.Add(ict);
            }
            
                
        }
            

    }
}